/*
 * Copyright: Tianjin Berheley Tech Co,.ltd, China
 * berheleyBI
 * net.mlw.vlh.adapter.jdbc.dynabean -> DefaultDynaBeanCahceAdapter.java
 * Created on 2009-9-17-上午09:44:19
 */
package net.mlw.vlh.adapter.jdbc.dynabean;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.mlw.vlh.DefaultListBackedValueList;
import net.mlw.vlh.ValueList;
import net.mlw.vlh.ValueListInfo;
import net.mlw.vlh.adapter.jdbc.AbstractDynaJdbcAdapter;
import net.mlw.vlh.adapter.jdbc.dynabean.fix.ResultSetDynaClass;
import net.mlw.vlh.adapter.jdbc.objectWrapper.ResultSetDecorator;
import net.mlw.vlh.adapter.jdbc.util.JdbcUtil;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

import org.apache.commons.beanutils.BasicDynaBean;
import org.apache.commons.beanutils.BasicDynaClass;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 类功能描述：
 * 
 * @author 
 *         
 */
public class WfDynaBeanAdvancedAdapter extends AbstractDynaJdbcAdapter
{

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * net.mlw.vlh.adapter.jdbc.AbstractJdbcAdapter#setSql(java.lang.String)
	 */

	private final Log LOGGER = LogFactory.getLog(getClass());
	Cache cache = null;

	public List processResultSet(String name, ResultSet result,
			int numberPerPage, ValueListInfo info) throws SQLException
	{
		Element element = null;
		String cacheKey = null;
		if (cache != null)
		{
			cacheKey = getCacheKey(name, numberPerPage, info);
			element = cache.get(cacheKey);
			if (element != null)
				return (List) element.getValue();

		}
		List list = new ArrayList();
		ResultSetDynaClass rsdc = new ResultSetDynaClass(result, false, isUseName());
		BasicDynaClass bdc = new BasicDynaClass(name, BasicDynaBean.class, rsdc.getDynaProperties());

		int rowIndex = 0;
		for (Iterator rows = rsdc.iterator(); rows.hasNext()
				&& rowIndex < numberPerPage; rowIndex++)
		{
			try
			{
				DynaBean oldRow = (DynaBean) rows.next();
				DynaBean newRow = bdc.newInstance();

				DynaProperty[] properties = oldRow.getDynaClass().getDynaProperties();
				for (int i = 0, length = properties.length; i < length; i++)
				{
					String propertyName = properties[i].getName();
					Object value = oldRow.get(propertyName);
					newRow.set(propertyName, value);
				}

				list.add(newRow);
			} catch (Exception e)
			{
				LOGGER.error(e);
			}
		}
		if (cache != null)
		{
			element = new Element(cacheKey, (Serializable) list);
			cache.put(element);
		}
		return list;
	}

	private String getCacheKey(String name, int numberPerPage,
			ValueListInfo info)
	{
		StringBuffer sb = new StringBuffer(name + numberPerPage);
		Map filters = info.getFilters();
		String filter = null;
		Iterator it = filters.keySet().iterator();
		{
			filter = (String) it.next();
			sb.append(filter.toString());
			sb.append(filters.get(filter).toString());
		}
		sb.append(info.getSortingColumn());
		sb.append(info.getSortingDirection());
		return sb.toString();
	}

	public ValueList getValueList(String name, ValueListInfo info,String nativeSql)
	{
		if (info.getSortingColumn() == null)
		{
			info.setPrimarySortColumn(getDefaultSortColumn());
			info.setPrimarySortDirection(getDefaultSortDirectionInteger());
		}

		int numberPerPage = info.getPagingNumberPer();

		if (numberPerPage == Integer.MAX_VALUE)
		{
			numberPerPage = getDefaultNumberPerPage();
			info.setPagingNumberPer(numberPerPage);
		}

		Connection connection = null;
		PreparedStatement statement = null;
		ResultSet result = null;

		try
		{
			boolean doSqlPaging = ((getAdapterType() & DO_PAGE) == 0);

			connection = getConnectionCreator().createConnection();

			StringBuffer query = (getSqlPagingSupport() != null) ? getSqlPagingSupport()
					.getPagedQuery(connection.getMetaData().getDatabaseProductName(),nativeSql)
					: new StringBuffer(nativeSql);
			statement = getStatementBuilder().generate(connection, query,
					info.getFilters(),
					getSqlPagingSupport() == null && doSqlPaging);

			if (LOGGER.isDebugEnabled())
			{
				LOGGER.debug(query.toString());
			}
			if (isShowSql())
			{
				LOGGER.warn("sql: " + query.toString());
			}
			result = getResultSet(statement, info);

			if (getSqlPagingSupport() != null)
			{
				PreparedStatement countStatement = null;
				ResultSet countResult = null;

				try
				{
					StringBuffer countQuery = getSqlPagingSupport().getCountQuery(nativeSql);
					countStatement = getStatementBuilder().generate(connection, countQuery, info.getFilters(), false);
					if (isShowSql())
					{
						LOGGER.warn("count sql: " + countQuery.toString());
					}

					countResult = countStatement.executeQuery();
					if (countResult.next())
					{
						info.setTotalNumberOfEntries(countResult.getInt(1));
					}
				} finally
				{
					JdbcUtil.close(countResult, countStatement, null);
				}

			} else if (doSqlPaging)
			{
				result.last();
				int totalRows = result.getRow();
				info.setTotalNumberOfEntries(totalRows);

				if (numberPerPage == 0)
				{
					numberPerPage = getDefaultNumberPerPage();
				}

				int pageNumber = info.getPagingPage();
				if (pageNumber > 1)
				{
					if ((pageNumber - 1) * numberPerPage > totalRows)
					{
						pageNumber = ((totalRows - 1) / numberPerPage) + 1;
						info.setPagingPage(pageNumber);
					}
				}

				if (pageNumber > 1)
				{
					result.absolute((pageNumber - 1) * numberPerPage);
				} else
				{
					result.beforeFirst();
				}
			}

			List list = processResultSet(name, result,
					(doSqlPaging) ? numberPerPage : Integer.MAX_VALUE, info);

			if (!doSqlPaging)
			{
				info.setTotalNumberOfEntries(list.size());
			}

			return new DefaultListBackedValueList(list, info);

		} catch (Exception e)
		{
			LOGGER.error(e);
			throw new RuntimeException(e);
		} finally
		{
			getConnectionCreator().close(result, statement, connection);
		}
	}

	private ResultSet getResultSet(PreparedStatement statement,
			ValueListInfo info) throws SQLException
	{
		if (getValidator() == null)
		{
			return statement.executeQuery();
		} else
		{
			getValidator().setValueListInfo(info);
			return new ResultSetDecorator(statement.executeQuery(),
					getValidator());
		}
	}

	/**
	 * @return Returns the cache.
	 */
	public Cache getCache()
	{
		return cache;
	}

	/**
	 * @param cache
	 *            The cache to set.
	 */
	public void setCache(Cache cache)
	{
		this.cache = cache;
	}

}
